package com.atguigu.dynamic.config;

import com.atguigu.dynamic.annotation.Type;
import com.atguigu.dynamic.aspect.DynamicDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 动态数据源配置类
 *
 * @author szj
 * @since 2021-03-21 16:27
 */
@Slf4j
@Configuration
@MapperScan(value = "com.atguigu.dynamic.mapper", sqlSessionFactoryRef = "dynamicSqlSessionFactory")
public class DataSourceConfig {

    /**
     * 从配置文件中获取 User 数据源的配置信息，并注入
     *
     * @return javax.sql.DataSource
     * @author szj
     * @since 2021/3/22 12:04
     */
    @ConfigurationProperties(prefix = "spring.datasource.user")
    @Bean("userDataSource")
    public DataSource userDataSource() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 从配置文件中获取 Order 数据源的配置信息，并注入
     *
     * @return javax.sql.DataSource
     * @author szj
     * @since 2021/3/22 12:05
     */
    @ConfigurationProperties(prefix = "spring.datasource.order")
    @Bean("orderDataSource")
    public DataSource orderDataSource() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 使用动态数据源 DynamicDataSource 包装 User 数据源与 Order 数据源
     *
     * @param userDataSource  User 数据源
     * @param orderDataSource Order 数据源
     * @return com.atguigu.dynamic.aspect.DynamicDataSource
     * @author szj
     * @since 2021/3/22 12:06
     */
    @Bean("dynamicDataSource")
    DynamicDataSource dynamicDataSource(@Qualifier("userDataSource") DataSource userDataSource, @Qualifier("orderDataSource") DataSource orderDataSource) {
        ConcurrentHashMap<Object, Object> targetDataSources = new ConcurrentHashMap<>(2);
        targetDataSources.put(Type.USER, userDataSource);
        targetDataSources.put(Type.ORDER, orderDataSource);
        return new DynamicDataSource(userDataSource, targetDataSources);
    }

    /**
     * 使用动态数据源类替代普通数据源注入 SqlSession工厂 sqlSessionFactoryBean，并返回 SqlSessionFactory实例
     *
     * @param dynamicDataSource 动态数据源
     * @return org.apache.ibatis.session.SqlSessionFactory
     * @author szj
     * @since 2021/3/22 12:07
     */
    @Primary
    @Bean("dynamicSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactoryBean(@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dynamicDataSource);
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setDefaultFetchSize(100);
        configuration.setDefaultStatementTimeout(30);
        sqlSessionFactoryBean.setConfiguration(configuration);
        return sqlSessionFactoryBean.getObject();
    }

    /**
     * 使用动态数据源替代普通数据源注入事务管理器 DataSourceTransactionManager
     *
     * @param dynamicDataSource 动态数据源
     * @return org.springframework.transaction.PlatformTransactionManager
     * @author szj
     * @since 2021/3/22 12:08
     */
    @Primary
    @Bean(value = "dynamicTransactionManager")
    public PlatformTransactionManager dynamicTransactionManager(@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }
}
